/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ar.uba.fi.RSACryptoFiuba.view.commons;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigInteger;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.LayoutStyle;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;

import org.apache.commons.lang3.math.NumberUtils;

import ar.uba.fi.RSACryptoFiuba.model.RSACalculator;

@SuppressWarnings("serial")
public class EvaluationInteractionPanel extends JPanel {

	protected static final int PLUS_OPERATION = 0;
	protected static final int MINUS_OPERATION = 1;
	protected static final int MULTIPLY_OPERATION = 2;
	protected static final int DIVIDE_OPERATION = 3;
	protected static final int PRIME_OPERATION = 4;
	protected static final int COPRIME_OPERATION = 5;
	protected static final int TO_ASCII_OPERATION = 6;
	protected static final int FROM_ASCII_OPERATION = 7;
	protected static final int MOD_MULTIPLICATIVE_INVERSE_OPERATION = 8;
	protected static final int MOD_OPERATION = 9;
	protected static final int EXP_OPERATION = 10;	
	protected static final int NO_OPERATION = 99;
	
	
	private String operation;
    private JPanel calculatorPanel;
    private JLabel operationLabel;
    private JPanel operationPanel;
    private JTextField operationValue;
    
    private JButton plusButton;
    private JButton minusButton;
    private JButton multiplyButton;
    private JButton divideButton;
    private JButton primeButton;
    private JButton coprimeButton;
    private JButton toASCIIButton;
    private JButton fromASCIIButton;
    private JButton equalsButton;
    private JButton expButton;
    private JButton modButton;
    private JButton multiplicativeInverseButton;
    private JTextField resultTextField;
    private JLabel errorMessageIcon;
    
    private String firstOperand;
    private String secondOperand;
    private int operationType;
    	
    public EvaluationInteractionPanel(String operation) {
    	this.operation = operation;
    	this.firstOperand = "";
    	this.secondOperand = "";
    	operationType = NO_OPERATION;
        initComponents();
    }
                         
    private void initComponents() {
    	calculatorPanel = new JPanel();
    	
    	resultTextField = new JTextField(20);
    	resultTextField.setMaximumSize(new Dimension(16, 26));
    	resultTextField.setMinimumSize(new Dimension(16, 26));
    	resultTextField.setMaximumSize(resultTextField.getMinimumSize());
    	resultTextField.setHorizontalAlignment(JTextField.RIGHT);
    	
    	plusButton = new JButton();
        plusButton.setFont(new Font("Ubuntu", 0, 10));
        plusButton.setText("+");
        plusButton.setMaximumSize(new Dimension(18, 20));
        plusButton.setMinimumSize(new Dimension(18, 20));
        plusButton.setPreferredSize(new Dimension(18, 20));
        plusButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				firstOperand = resultTextField.getText();
				operationType = PLUS_OPERATION;
				resultTextField.setText("");
				resultTextField.requestFocusInWindow();
			}
		});
        
        minusButton = new JButton();
        minusButton.setFont(new Font("Ubuntu", 0, 10));
        minusButton.setText("-");
        minusButton.setMaximumSize(new Dimension(18, 20));
        minusButton.setMinimumSize(new Dimension(18, 20));
        minusButton.setPreferredSize(new Dimension(18, 20));
        minusButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				firstOperand = resultTextField.getText();
				operationType = MINUS_OPERATION;
				resultTextField.setText("");
				resultTextField.requestFocusInWindow();
			}
		});
                
        multiplyButton = new JButton();
        multiplyButton.setFont(new Font("Ubuntu", 0, 10));
        multiplyButton.setText("*");
        multiplyButton.setMaximumSize(new Dimension(18, 20));
        multiplyButton.setMinimumSize(new Dimension(18, 20));
        multiplyButton.setPreferredSize(new Dimension(18, 20));
        multiplyButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				firstOperand = resultTextField.getText();
				operationType = MULTIPLY_OPERATION;
				resultTextField.setText("");
				resultTextField.requestFocusInWindow();
			}
		});
        
        divideButton = new JButton();
        divideButton.setFont(new Font("Ubuntu", 0, 10));
        divideButton.setText("/");
        divideButton.setMaximumSize(new Dimension(18, 20));
        divideButton.setMinimumSize(new Dimension(18, 20));
        divideButton.setPreferredSize(new Dimension(18, 20));
        divideButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				firstOperand = resultTextField.getText();
				operationType = DIVIDE_OPERATION;
				resultTextField.setText("");
				resultTextField.requestFocusInWindow();
			}
		});
        
        primeButton = new JButton();
        primeButton.setFont(new Font("Ubuntu", 0, 10));
        primeButton.setText("Primo");
        primeButton.setToolTipText("[Primo]: Se genera un número primo al azar");
        primeButton.setMaximumSize(new Dimension(18, 20));
        primeButton.setMinimumSize(new Dimension(18, 20));
        primeButton.setPreferredSize(new Dimension(18, 20));
        primeButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				
				Integer result = RSACalculator.getRandomPrime(); 
				resultTextField.setText(result.toString());
				firstOperand = "";
				secondOperand = "";
				operationType = NO_OPERATION;
				resultTextField.requestFocusInWindow();
			}
		});
        
        coprimeButton = new JButton();
        coprimeButton.setFont(new Font("Ubuntu", 0, 10));
        coprimeButton.setText("Coprimo");
        coprimeButton.setToolTipText("(a) [Coprimo]: Se genera un número coprimo de a");
        coprimeButton.setMaximumSize(new Dimension(18, 20));
        coprimeButton.setMinimumSize(new Dimension(18, 20));
        coprimeButton.setPreferredSize(new Dimension(18, 20));
        coprimeButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				try{
					firstOperand = resultTextField.getText();
					Integer result = RSACalculator.getCoprime(new Integer(firstOperand));
					resultTextField.setText(result.toString());
				} catch (Exception ex) {
					firstOperand = "Error!!!";
					resultTextField.setText(firstOperand);
				}
				resultTextField.requestFocusInWindow();
			}
		});
        
        toASCIIButton = new JButton();
        toASCIIButton.setFont(new Font("Ubuntu", 0, 10));
        toASCIIButton.setText("a ASCII");
        toASCIIButton.setToolTipText("(a) [a ASCII]: Se obtiene la representación en ASCII de a");
        toASCIIButton.setMaximumSize(new Dimension(18, 20));
        toASCIIButton.setMinimumSize(new Dimension(18, 20));
        toASCIIButton.setPreferredSize(new Dimension(18, 20));
        toASCIIButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				try{
					firstOperand = resultTextField.getText();
					String result = (!firstOperand.isEmpty()) ? RSACalculator.getASCIIRepresentation(firstOperand) : "Error!!!";
					resultTextField.setText(result);
				} catch (Exception ex) {
					firstOperand = "Error!!!";
					resultTextField.setText(firstOperand);
				}
				resultTextField.requestFocusInWindow();
			}
		});
        
        fromASCIIButton = new JButton();
        fromASCIIButton.setFont(new Font("Ubuntu", 0, 10));
        fromASCIIButton.setText("de ASCII");
        fromASCIIButton.setToolTipText("(a) [de ASCII]: Se obtiene el texto correspondiente a la respresentación en ASCII a");
        fromASCIIButton.setMaximumSize(new Dimension(18, 20));
        fromASCIIButton.setMinimumSize(new Dimension(18, 20));
        fromASCIIButton.setPreferredSize(new Dimension(18, 20));
        fromASCIIButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				try{
					firstOperand = resultTextField.getText();
					String result = (NumberUtils.isDigits(firstOperand)) ? RSACalculator.getTextFromASCII(firstOperand) : "Error!!!";
					resultTextField.setText(result);
					firstOperand = result;
				} catch (Exception ex) {
					firstOperand = "Error!!!";
					resultTextField.setText(firstOperand);
				}
				resultTextField.requestFocusInWindow();
			}
		});
        
        multiplicativeInverseButton = new JButton();
        multiplicativeInverseButton.setFont(new Font("Ubuntu", 0, 10));
        multiplicativeInverseButton.setText("Inv Mult");
        multiplicativeInverseButton.setToolTipText("(a) [Inv Mult] (mod) [=]: Se calcula el inverso multiplicativo de a en módulo mod");
        multiplicativeInverseButton.setMaximumSize(new Dimension(18, 20));
        multiplicativeInverseButton.setMinimumSize(new Dimension(18, 20));
        multiplicativeInverseButton.setPreferredSize(new Dimension(18, 20));
        multiplicativeInverseButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				try{
					firstOperand = resultTextField.getText();
					operationType = MOD_MULTIPLICATIVE_INVERSE_OPERATION;
					resultTextField.setText("");
				} catch (Exception ex) {
					firstOperand = "Error!!!";
					resultTextField.setText(firstOperand);
				}
				resultTextField.requestFocusInWindow();
			}
		});
        
        modButton = new JButton();
        modButton.setFont(new Font("Ubuntu", 0, 10));
        modButton.setText("Mod");
        modButton.setToolTipText("(a) [Mod] (b) [=]: Se calcula el resto de la división de a y b");
        modButton.setMaximumSize(new Dimension(18, 20));
        modButton.setMinimumSize(new Dimension(18, 20));
        modButton.setPreferredSize(new Dimension(18, 20));
        modButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				try{
					firstOperand = resultTextField.getText();
					operationType = MOD_OPERATION;
					resultTextField.setText("");
				} catch (Exception ex) {
					firstOperand = "Error!!!";
					resultTextField.setText(firstOperand);
				}
				resultTextField.requestFocusInWindow();
			}
		});

        expButton = new JButton();
        expButton.setFont(new Font("Ubuntu", 0, 10));
        expButton.setText("exp");
        expButton.setToolTipText("(a) [exp] (b) [=]: Se calcula el valor de a elevado a la b");
        expButton.setMaximumSize(new Dimension(18, 20));
        expButton.setMinimumSize(new Dimension(18, 20));
        expButton.setPreferredSize(new Dimension(18, 20));
        expButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				try{
					firstOperand = resultTextField.getText();
					operationType = EXP_OPERATION;
					resultTextField.setText("");
				} catch (Exception ex) {
					firstOperand = "Error!!!";
					resultTextField.setText(firstOperand);
				}
				resultTextField.requestFocusInWindow();
			}
		});
        
        equalsButton = new JButton();
        equalsButton.setFont(new Font("Ubuntu", 0, 10));
        equalsButton.setText("=");
        equalsButton.setMaximumSize(new Dimension(18, 20));
        equalsButton.setMinimumSize(new Dimension(18, 20));
        equalsButton.setPreferredSize(new Dimension(18, 20));
        equalsButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				secondOperand = resultTextField.getText();
				Integer integerResult;
				BigInteger bigIntegerResult;
				try {
					switch (operationType) {
					case PLUS_OPERATION:
						integerResult = RSACalculator.add(new Integer(firstOperand), new Integer(secondOperand));
						resultTextField.setText(integerResult.toString());
						break;
					case MINUS_OPERATION:
						integerResult = RSACalculator.extract(new Integer(firstOperand), new Integer(secondOperand));
						resultTextField.setText(integerResult.toString());
						break;
					case MULTIPLY_OPERATION:
						integerResult = RSACalculator.multiply(new Integer(firstOperand), new Integer(secondOperand));
						resultTextField.setText(integerResult.toString());
						break;
					case DIVIDE_OPERATION:
						integerResult = RSACalculator.divide(new Integer(firstOperand), new Integer(secondOperand));
						resultTextField.setText(integerResult.toString());
						break;
					case MOD_MULTIPLICATIVE_INVERSE_OPERATION:
						integerResult = RSACalculator.getModMultiplicativeInverse(new Integer(firstOperand), new Integer(secondOperand));
						resultTextField.setText(integerResult.toString());
						break;
					case MOD_OPERATION:
						bigIntegerResult = RSACalculator.mod(new BigInteger(firstOperand), new BigInteger(secondOperand));
						resultTextField.setText(bigIntegerResult.toString());
						break;
					case EXP_OPERATION:
						bigIntegerResult = RSACalculator.exp(new BigInteger(firstOperand), new Integer(secondOperand));
						resultTextField.setText(bigIntegerResult.toString());
						break;
					default:
						break;
					}
					firstOperand = resultTextField.getText();
				} catch (Exception ex) {
					firstOperand = "Error!!!";
					resultTextField.setText(firstOperand);
				}
				secondOperand = "";
				operationType = NO_OPERATION;
				resultTextField.requestFocusInWindow();
			}
		});

        operationPanel = new JPanel();
        
        operationValue = new JTextField();       
        operationValue.setFont(new Font("Ubuntu", 1, 18));       
        operationValue.addAncestorListener(new AncestorListener() {
			public void ancestorAdded(AncestorEvent event) {
				operationValue.requestFocusInWindow();
			}

			public void ancestorRemoved(AncestorEvent event) {}

			public void ancestorMoved(AncestorEvent event) {}
		});
        
        operationLabel = new JLabel();
        operationLabel.setFont(new Font("Ubuntu", 1, 18));
        errorMessageIcon = new JLabel();
        errorMessageIcon.setVisible(false);

        GroupLayout stepDescriptionPanelLayout = new GroupLayout(calculatorPanel);
        calculatorPanel.setLayout(stepDescriptionPanelLayout);
        stepDescriptionPanelLayout.setHorizontalGroup(
            stepDescriptionPanelLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(stepDescriptionPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(stepDescriptionPanelLayout.createParallelGroup(Alignment.TRAILING)
                    .addComponent(resultTextField, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(stepDescriptionPanelLayout.createSequentialGroup()
                        .addGroup(stepDescriptionPanelLayout.createParallelGroup(Alignment.LEADING)
                            .addComponent(multiplyButton, GroupLayout.DEFAULT_SIZE, 65, Short.MAX_VALUE)
                            .addComponent(divideButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(plusButton, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(minusButton, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(ComponentPlacement.RELATED)
                        .addGroup(stepDescriptionPanelLayout.createParallelGroup(Alignment.LEADING, false)
                            .addComponent(coprimeButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(fromASCIIButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(primeButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(toASCIIButton, GroupLayout.PREFERRED_SIZE, 80, GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(ComponentPlacement.RELATED)
                        .addGroup(stepDescriptionPanelLayout.createParallelGroup(Alignment.LEADING)
                            .addComponent(modButton, Alignment.TRAILING, GroupLayout.PREFERRED_SIZE, 80, GroupLayout.PREFERRED_SIZE)
                            .addComponent(multiplicativeInverseButton, Alignment.TRAILING, GroupLayout.PREFERRED_SIZE, 80, GroupLayout.PREFERRED_SIZE)
                            .addComponent(expButton, Alignment.TRAILING, GroupLayout.PREFERRED_SIZE, 80, GroupLayout.PREFERRED_SIZE)
                            .addComponent(equalsButton, Alignment.TRAILING, GroupLayout.PREFERRED_SIZE, 80, GroupLayout.PREFERRED_SIZE))))
                .addContainerGap())
        );
        stepDescriptionPanelLayout.setVerticalGroup(
            stepDescriptionPanelLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(stepDescriptionPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(resultTextField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(ComponentPlacement.RELATED)
                .addGroup(stepDescriptionPanelLayout.createParallelGroup(Alignment.BASELINE)
                    .addComponent(primeButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(multiplicativeInverseButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(plusButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(ComponentPlacement.RELATED)
                .addGroup(stepDescriptionPanelLayout.createParallelGroup(Alignment.BASELINE)
                    .addComponent(coprimeButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(modButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(minusButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(ComponentPlacement.RELATED)
                .addGroup(stepDescriptionPanelLayout.createParallelGroup(Alignment.BASELINE)
                    .addComponent(toASCIIButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(expButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(multiplyButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(ComponentPlacement.RELATED)
                .addGroup(stepDescriptionPanelLayout.createParallelGroup(Alignment.BASELINE)
                    .addComponent(fromASCIIButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(equalsButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(divideButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        operationLabel.setFont(new Font("Ubuntu", 1, 18)); 
        operationLabel.setText(this.operation);

        errorMessageIcon.setIcon(new ImageIcon(getClass().getResource("/error.png")));
        errorMessageIcon.setToolTipText("este es un mensaje de error");

        GroupLayout stepOperationPanelLayout = new GroupLayout(operationPanel);
        operationPanel.setLayout(stepOperationPanelLayout);
        stepOperationPanelLayout.setHorizontalGroup(
            stepOperationPanelLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(Alignment.TRAILING, stepOperationPanelLayout.createSequentialGroup()
                .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(stepOperationPanelLayout.createParallelGroup(Alignment.LEADING)
                    .addComponent(errorMessageIcon)
                    .addComponent(operationLabel)
                    .addComponent(operationValue, GroupLayout.PREFERRED_SIZE, 255, GroupLayout.PREFERRED_SIZE))
                .addGap(31, 31, 31))
        );
        stepOperationPanelLayout.setVerticalGroup(
            stepOperationPanelLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(stepOperationPanelLayout.createSequentialGroup()
                .addGap(18, 18, 18)
                .addComponent(operationLabel)
                .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(operationValue, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(ComponentPlacement.UNRELATED)
                .addComponent(errorMessageIcon)
                .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        GroupLayout layout = new GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(47, 47, 47)
                .addComponent(calculatorPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, Short.MAX_VALUE)
                .addComponent(operationPanel, GroupLayout.PREFERRED_SIZE, 278, GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(Alignment.LEADING)
            .addComponent(calculatorPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(operationPanel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
    }                
    
    public void setOperationValue(String value){
    	this.operationValue.setText(value);
    }
    
    public String getOperationValue(){
    	return this.operationValue.getText();
    }
    
    public JTextField getOperationTextField(){
    	return this.operationValue;
    }
    
    public void setToolTip(String toolTipmessage){
    	this.errorMessageIcon.setVisible(true);
    	this.errorMessageIcon.setToolTipText(toolTipmessage);
    }
    
    public void resetToolTip(){
    	this.errorMessageIcon.setVisible(false);
    	this.errorMessageIcon.setToolTipText("");
    }
                       
}

